/*******************************************************/
/* file: ports.c                                       */
/* abstract:  This file contains the routines to       */
/*            output values on the JTAG ports, to read */
/*            the TDO bit, and to read a byte of data  */
/*            from the prom                            */
/* Revisions:                                          */
/* 12/01/2008:  Same code as before (original v5.01).  */
/*              Updated comments to clarify instructions.*/
/*              Add print in setPort for xapp058_example.exe.*/
/*******************************************************/
#include "xsvf_ports.h"
/*#include "prgispx.h"*/

#include "stdio.h"

t_lua_callback_param g_xsvf_callback_param;

/* setPort:  Implement to set the named JTAG signal (p) to the new value (v).*/
/* if in debugging mode, then just set the variables */
void setPort(short p,short val)
{
	if( g_xsvf_callback_param._L == NULL) {
		return;
	}

	lua_rawgeti(g_xsvf_callback_param._L, LUA_REGISTRYINDEX, g_xsvf_callback_param.callback_ref_setPort); /* push stored function */

	/* push arg to stack*/
	lua_pushnumber (g_xsvf_callback_param._L, (int)p);
    lua_pushnumber (g_xsvf_callback_param._L, (int)val);

	/* call function*/
	int ret = lua_pcall(g_xsvf_callback_param._L, 2, 0, 0);
	if(ret != LUA_OK ) {
		printf("<XSVF>setPort: Run callback_ref_setPort function error, code = %d\r\n", ret);
	}
}

/* toggle tck LH.  No need to modify this code.  It is output via setPort. */
void pulseClock()
{
    setPort(TCK,0);  /* set the TCK port to low  */
    setPort(TCK,1);  /* set the TCK port to high */
}


/* readByte:  Implement to source the next byte from your XSVF file location */
/* read in a byte of data from the prom */
void readByte(unsigned char *data)
{
    int top = 0;

	if( g_xsvf_callback_param._L == NULL) {
		return;
	}

	lua_rawgeti(g_xsvf_callback_param._L, LUA_REGISTRYINDEX, g_xsvf_callback_param.callback_ref_readByte); /* push stored function */

	/* call function*/
	int ret = lua_pcall(g_xsvf_callback_param._L, 0, 1, 0);
	if(ret != LUA_OK ) {
		printf("<XSVF>readByte: Run callback_ref_readByte function error, code = %d\r\n", ret);
        return;
	}

    top = lua_gettop(g_xsvf_callback_param._L);
    //printf("<XSVF>readByte: top = %d\r\n", top);
    if(top >= 1) {
        if(lua_isnumber(g_xsvf_callback_param._L, -1)) {
            *data = (unsigned char)lua_tointeger(g_xsvf_callback_param._L, -1);
            //printf("<XSVF>readByte: *data = %d\r\n", *data);           
        }
        lua_pop(g_xsvf_callback_param._L, top);//clear stack
    }
}

/* readTDOBit:  Implement to return the current value of the JTAG TDO signal.*/
/* read the TDO bit from port */
unsigned char readTDOBit()
{
    int top = 0, read = 0;

	if( g_xsvf_callback_param._L == NULL) {
		return 0;
	}

	lua_rawgeti(g_xsvf_callback_param._L, LUA_REGISTRYINDEX, g_xsvf_callback_param.callback_ref_readTDOBit); /* push stored function */

	/* call function*/
	int ret = lua_pcall(g_xsvf_callback_param._L, 0, 1, 0);
	if(ret != LUA_OK ) {
		printf("<XSVF>readTDOBit: Run callback_ref_readTDOBit function error, code = %d\r\n", ret);
        return 0;
	}

    top = lua_gettop(g_xsvf_callback_param._L);
    //printf("<XSVF>readTDOBit: top = %d\r\n", top);
    if(top >= 1) {
        if(lua_isnumber(g_xsvf_callback_param._L, -1)) {
            read = (unsigned char)lua_tointeger(g_xsvf_callback_param._L, -1);
            //printf("<XSVF>readTDOBit: read = %d\r\n", read);
        }
        lua_pop(g_xsvf_callback_param._L, top);//clear stack
    }

    return read;
}

/* waitTime:  Implement as follows: */
/* REQUIRED:  This function must consume/wait at least the specified number  */
/*            of microsec, interpreting microsec as a number of microseconds.*/
/* REQUIRED FOR SPARTAN/VIRTEX FPGAs and indirect flash programming:         */
/*            This function must pulse TCK for at least microsec times,      */
/*            interpreting microsec as an integer value.                     */
/* RECOMMENDED IMPLEMENTATION:  Pulse TCK at least microsec times AND        */
/*                              continue pulsing TCK until the microsec wait */
/*                              requirement is also satisfied.               */
void waitTime(long microsec)
{
    usleep(microsec);

#if 0
    static long tckCyclesPerMicrosec    = 1; /* must be at least 1 */
    long        tckCycles   = microsec * tckCyclesPerMicrosec;
    long        i;

    /* This implementation is highly recommended!!! */
    /* This implementation requires you to tune the tckCyclesPerMicrosec 
       variable (above) to match the performance of your embedded system
       in order to satisfy the microsec wait time requirement. */
    for ( i = 0; i < tckCycles; ++i )
    {
        pulseClock();
    }
#endif

#if 0
    /* Alternate implementation */
    /* For systems with TCK rates << 1 MHz;  Consider this implementation. */
    /* This implementation does not work with Spartan-3AN or indirect flash
       programming. */
    if ( microsec >= 50L )
    {
        /* Make sure TCK is low during wait for XC18V00/XCFxxS */
        /* Or, a running TCK implementation as shown above is an OK alternate */
        setPort( TCK, 0 );

        /* Use Windows Sleep().  Round up to the nearest millisec */
        _sleep( ( microsec + 999L ) / 1000L );
    }
    else    /* Satisfy FPGA JTAG configuration, startup TCK cycles */
    {
        for ( i = 0; i < microsec;  ++i )
        {
            pulseClock();
        }
    }
#endif

#if 0
    /* Alternate implementation */
    /* This implementation is valid for only XC9500/XL/XV, CoolRunner/II CPLDs, 
       XC18V00 PROMs, or Platform Flash XCFxxS/XCFxxP PROMs.  
       This implementation does not work with FPGAs JTAG configuration. */
    /* Make sure TCK is low during wait for XC18V00/XCFxxS PROMs */
    /* Or, a running TCK implementation as shown above is an OK alternate */
    setPort( TCK, 0 );
    /* Use Windows Sleep().  Round up to the nearest millisec */
    _sleep( ( microsec + 999L ) / 1000L );
#endif
}
